package com.laifeng.sopcastsdk.controller;

import android.media.MediaCodec;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.laifeng.sopcastsdk.audio.OnAudioEncodeListener;
import com.laifeng.sopcastsdk.configuration.AudioConfiguration;
import com.laifeng.sopcastsdk.configuration.VideoConfiguration;
import com.laifeng.sopcastsdk.controller.audio.IAudioController;
import com.laifeng.sopcastsdk.controller.video.IVideoController;
import com.laifeng.sopcastsdk.stream.packer.Packer;
import com.laifeng.sopcastsdk.stream.packer.flv.FlvPacker;
import com.laifeng.sopcastsdk.stream.packer.rtmp.RtmpPacker;
import com.laifeng.sopcastsdk.stream.sender.Sender;
import com.laifeng.sopcastsdk.stream.sender.local.LocalSender;
import com.laifeng.sopcastsdk.stream.sender.rtmp.RtmpSender;
import com.laifeng.sopcastsdk.utils.SopCastLog;
import com.laifeng.sopcastsdk.utils.SopCastUtils;
import com.laifeng.sopcastsdk.video.OnVideoEncodeListener;

import java.nio.ByteBuffer;

import static com.laifeng.sopcastsdk.constant.SopCastConstant.TAG;

/**
 * @Title: StreamController
 * @Package com.laifeng.sopcastsdk.controller
 * @Description:
 * @Author Jim
 * @Date 16/9/14
 * @Time 上午11:44
 * @Version
 */

public class StreamController implements OnAudioEncodeListener, OnVideoEncodeListener, Packer.OnPacketListener {

    //flv packer and sender
    private FlvPacker mFlvPacker;
    private LocalSender mFlvSender;

    //rtmp packer and sender
    private RtmpPacker mRtmpPacker;
    private RtmpSender mRtmpSender;

    private IVideoController mVideoController;
    private IAudioController mAudioController;

    public StreamController(IVideoController videoProcessor, IAudioController audioProcessor) {

        if (videoProcessor == null || audioProcessor == null) {
            throw new RuntimeException("Video and audio processor must not be null.");
        }

        mAudioController = audioProcessor;
        mVideoController = videoProcessor;
    }

    public void setAudioConfiguration(AudioConfiguration audioConfiguration) {
        mAudioController.setAudioConfiguration(audioConfiguration);
    }

    public void mute(boolean mute) {
        mAudioController.mute(mute);
    }

    public int getSessionId() {
        return mAudioController.getSessionId();
    }

    public boolean setVideoBps(int bps) {
        return mVideoController.setVideoBps(bps);
    }

    @Override
    public void onAudioEncode(ByteBuffer bb, MediaCodec.BufferInfo bi) {
        if (mFlvPacker != null) {
            mFlvPacker.onAudioData(bb, bi);
        }

        if (mRtmpPacker != null) {
            mRtmpPacker.onAudioData(bb, bi);
        }
    }

    @Override
    public void onVideoEncode(ByteBuffer bb, MediaCodec.BufferInfo bi) {
        if (mFlvPacker != null) {
            mFlvPacker.onVideoData(bb, bi);
        }
    }

    @Override
    public void onLiveVideoEncode(ByteBuffer bb, MediaCodec.BufferInfo bi) {
        if (mRtmpPacker != null) {
            mRtmpPacker.onVideoData(bb, bi);
        }
    }

    @Override
    public void onPacket(byte[] data, int packetType) {
        if (mFlvSender != null) {
            mFlvSender.onData(data, packetType);
        }
    }

    @Override
    public void onPacketLiveStream(byte[] data, int packetType) {
        if (mRtmpSender != null) {
            mRtmpSender.onData(data, packetType);
        }
    }

    @Override
    public boolean onTransferFile() {
        if (mFlvSender != null) {
            return mFlvSender.onTransferFile();
        }

        return false;
    }

    public void setFlvPackerSender(FlvPacker packer, LocalSender sender) {
        mFlvPacker = packer;
        mFlvSender = sender;
        mFlvPacker.setPacketListener(this);
    }

    public void setRtmpPackerSender(RtmpPacker packer, RtmpSender sender) {
        mRtmpPacker = packer;
        mRtmpSender = sender;
        mRtmpPacker.setPacketListener(this);
    }


    public synchronized void startRecording() {
        SopCastUtils.processNotUI(new SopCastUtils.INotUIProcessor() {
            @Override
            public void process() {
                if (mFlvPacker == null) {
                    return;
                }

                if (mFlvSender == null) {
                    return;
                }

                Log.e("YJQ", "start recording...................");

                mFlvPacker.start();
                mFlvSender.start();
                mVideoController.startRecord(StreamController.this);
                mAudioController.setAudioEncodeListener(StreamController.this);
                mAudioController.start();
            }
        });
    }

    public synchronized void stopRecording() {
        SopCastUtils.processNotUI(new SopCastUtils.INotUIProcessor() {
            @Override
            public void process() {

                if (mRtmpPacker == null || !mRtmpPacker.isRunning()) {
                    mVideoController.stopRecord();
                    mAudioController.setAudioEncodeListener(null);
                    mAudioController.stop();
                }

                if (mFlvSender != null) {
                    mFlvSender.stop();
                }
                if (mFlvPacker != null) {
                    mFlvPacker.stop();
                }
            }
        });
    }

    public synchronized void startLiving() {
        SopCastUtils.processNotUI(new SopCastUtils.INotUIProcessor() {
            @Override
            public void process() {
                if (mRtmpPacker == null) {
                    return;
                }

                if (mRtmpSender == null) {
                    return;
                }

                if (mVideoController.isLiving()) {
                    Log.e("YJQ", "Is living state now......");
                    return;
                }

                mRtmpSender.setSenderListener(mSenderListener);
                mRtmpSender.setAddress("rtmp://39.107.80.140:1935/live/test");
                mRtmpSender.connect();
            }
        });
    }

    private void startLivingInternal() {
        SopCastUtils.processNotUI(new SopCastUtils.INotUIProcessor() {
            @Override
            public void process() {
                if (mRtmpPacker == null) {
                    return;
                }

                if (mRtmpSender == null) {
                    return;
                }

                mRtmpPacker.start();
                mRtmpSender.start();

                mVideoController.startLive(StreamController.this);
                mAudioController.setAudioEncodeListener(StreamController.this);
                mAudioController.start();
            }
        });
    }

    public synchronized void stopLiving() {
        SopCastUtils.processNotUI(new SopCastUtils.INotUIProcessor() {
            @Override
            public void process() {
                if (mFlvPacker == null || !mFlvPacker.isRunning()) {
                    mVideoController.stopLive();
                    mAudioController.setAudioEncodeListener(null);
                    mAudioController.stop();
                }

                if (mRtmpSender != null) {
                    mRtmpSender.stop();
                }
                if (mRtmpPacker != null) {
                    mRtmpPacker.stop();
                }
            }
        });
    }

    private RtmpSender.OnSenderListener mSenderListener = new RtmpSender.OnSenderListener() {
        @Override
        public void onConnecting() {
            Log.e("YJQ", ">>>>>>>>>>>>>>>on connecting<<<<<<<<<<<<<<<");
        }

        @Override
        public void onConnected() {
            Log.e("YJQ", ">>>>>>>>>>>>>>>on connected<<<<<<<<<<<<<<<");
            startLivingInternal();
        }

        @Override
        public void onDisConnected() {
            Log.e("YJQ", ">>>>>>>>>>>>>>>on disConnected<<<<<<<<<<<<<<<");
            stopLiving();
        }

        @Override
        public void onPublishFail() {
            Log.e("YJQ", ">>>>>>>>>>>>>>>on publish failed<<<<<<<<<<<<<<<");
        }

        @Override
        public void onNetGood() {
        }

        @Override
        public void onNetBad() {
        }
    };
}
